package common

import (
	"crypto/hmac"
	"crypto/sha256"
	"encoding/hex"
	"fmt"
	"reflect"
	"regexp"
	"strconv"
	"strings"
	"unicode"
)

func StringToInt64(str string) int64 {
	num, _ := strconv.ParseInt(str, 10, 64)
	return num
}

func StringToInt(str string) int {
	num, _ := strconv.Atoi(str)
	return num
}

// DefStr x = a?:b
func DefStr(str, def string) string {
	if len(str) == 0 {
		return def
	}
	return str
}

// 大于０的默认返回int
func DefIntGtZero(a, b int) int {
	if a > 0 {
		return a
	}

	return b
}

// IfStr  cond ? a : b
func IfStr(cond bool, a, b string) string {
	if cond {
		return a
	}
	return b
}

// IfInt  cond ? a : b
func IfInt(cond bool, a, b int) int {
	if cond {
		return a
	}
	return b
}

// DefStr x = a?:b
func DefInt(num, def int) int {
	if num == 0 {
		return def
	}
	return num
}

func ToStringF(obj interface{}) string {
	if InterfaceIsNil(obj) {
		return ""
	}
	switch reflect.TypeOf(obj).Kind() {
	default:
		return fmt.Sprintf("%v", obj)
	case reflect.Float32, reflect.Float64:
		return fmt.Sprintf("%g", obj)
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
		reflect.Int8, reflect.Int, reflect.Int16, reflect.Int32, reflect.Int64:
		return fmt.Sprintf("%d", obj)
	}
}

func HmacSha256(data, secret string) []byte {
	h := hmac.New(sha256.New, []byte(secret))
	h.Write([]byte(data))
	return h.Sum(nil)
}

func HmacSha2562(data, secret string) string {
	h := hmac.New(sha256.New, []byte(secret))
	h.Write([]byte(data))
	return hex.EncodeToString(h.Sum(nil))
}

func ReverseStr(str string) string {
	bytes := []rune(str)
	for from, to := 0, len(bytes)-1; from < to; from, to = from+1, to-1 {
		bytes[from], bytes[to] = bytes[to], bytes[from]
	}
	str = string(bytes)
	return str
}

func StringToFloat(str string) float64 {
	fNum, _ := strconv.ParseFloat(str, 64)
	return fNum
}

func IsContainChinese(str string) bool {
	return regexp.MustCompile("[\u4e00-\u9fa5]").MatchString(str)
}

func IsProductId(str string) bool {
	//字符串长度为19位纯数字即商品id
	str = strings.TrimSpace(str)
	isNum, err := regexp.MatchString("\\d+", str)
	if err != nil {
		return false
	}
	if isNum && len(str) == 19 {
		return true
	}
	return false
}

//PhoneNumber format
func IsPhoneNumer(str string) bool {
	return regexp.MustCompile(`^1[3456789]\d{9}$`).MatchString(str)
}

//电话号码表达式
func IsPhoneNumberValidation(str string) bool {
	return regexp.MustCompile(`^([0-9]{3,4}-)?[0-9]{7,8}$`).MatchString(str)
}

func IsMatchPattern(pattern, targetStr string) bool {
	return regexp.MustCompile(pattern).MatchString(targetStr)
}

func FindSubMatch(pattern, targetStr string) []string {
	return regexp.MustCompile(pattern).FindStringSubmatch(targetStr)
}

func IsNumber(number string) bool {
	return IsMatchPattern(`^[1-9]{1}[0-9]*$`, number) || IsNumber2(number)
}

func IsNumber2(str string) bool {
	return regexp.MustCompile(`^[0-9]+$`).MatchString(str)
}

func IsNegativeNumber(number string) bool {
	return IsMatchPattern(`^-[1-9]{1}[0-9]*$`, number)
}

func IsPositiveNumber(number string) bool {
	return IsMatchPattern(`^[1-9]{1}[0-9]*$`, number)
}

func IsDate(dateStr string) bool {
	return IsMatchPattern(`^\d{4}-0\d|1[1-2]-0\d|1\d|2\d|3[0-1]$`, dateStr)
}

func IsTime(timeStr string) bool {
	return IsMatchPattern(`^2[0-3]|[0-1]\d:[0-5]\d:[0-5]\d$`, timeStr)
}

func IsDateTime(dateTimeStr string) bool {
	pattern := `^\d{4}-0\d|1[1-2]-0\d|1\d|2\d|3[0-1]\s+2[0-3]|[0-1]\d:[0-5]\d:[0-5]\d$`
	return IsMatchPattern(pattern, dateTimeStr)
}

func ConvertFirstLetterToUpper(str *string) {
	firstLetter := rune((*str)[0])
	if !unicode.IsUpper(firstLetter) {
		firstLetter = unicode.ToUpper(firstLetter)
	}
	*str = string(firstLetter) + (*str)[1:]
}

func GetClientOs(userAgent string) string {
	os := userAgent
	if os == "" {
		return "unknow"
	}
	switch {
	case IsMatchPattern(`(?i)win`, os):
		return "Windows"
	case IsMatchPattern(`(?i)mac`, os):
		return "MAC"
	case IsMatchPattern(`(?i)linux`, os):
		return "Linux"
	case IsMatchPattern(`(?i)unix`, os):
		return "Unix"
	case IsMatchPattern(`(?i)bsd`, os):
		return "BSD"
	default:
		return "Other"
	}
}

func GetBrowser(userAgent string) map[string]string {
	browser, browserVersion := "", ""
	agent := userAgent
	switch {
	case IsMatchPattern(`(?i)OmniWeb\/(v*)([^\s|;]+)`, agent):
		browser = "OmniWeb"
		browserVersion = FindSubMatch(`(?i)OmniWeb\/(v*)([^\s|;]+)`, agent)[2]
	case IsMatchPattern(`(?i)Netscape([\d]*)\/([^\s]+)`, agent):
		browser = "Netscape"
		browserVersion = FindSubMatch(`(?i)Netscape([\d]*)\/([^\s]+)`, agent)[2]
	case IsMatchPattern(`(?i)safari\/([^\s]+)`, agent):
		browser = "Safari"
		browserVersion = FindSubMatch(`(?i)safari\/([^\s]+)`, agent)[1]
	case IsMatchPattern(`(?i)MSIE\s([^\s|;]+)`, agent):
		browser = "Internet Explorer"
		browserVersion = FindSubMatch(`(?i)MSIE\s([^\s|;]+)`, agent)[1]
	case IsMatchPattern(`(?i)Opera[\s|\/]([^\s]+)`, agent):
		browser = "Opera"
		browserVersion = FindSubMatch(`(?i)Opera[\s|\/]([^\s]+)`, agent)[1]
	case IsMatchPattern(`(?i)NetCaptor\s([^\s|;]+)`, agent):
		browserVersion = FindSubMatch(`(?i)NetCaptor\s([^\s|;]+)`, agent)[1]
		browser = "(Internet Explorer " + browserVersion + " )" + " NetCaptor"
	case IsMatchPattern(`(?i)Maxthon`, agent):
		browserVersion = ""
		browser = "(Internet Explorer " + browserVersion + " )" + " Maxthon"
	case IsMatchPattern(`(?i)360SE`, agent):
		browserVersion = ""
		browser = "(Internet Explorer " + browserVersion + " )" + " 360SE"
	case IsMatchPattern(`(?i)SE 2.x`, agent):
		browserVersion = ""
		browser = "(Internet Explorer " + browserVersion + " )" + " 搜狗"
	case IsMatchPattern(`(?i)FireFox\/([^\s]+)`, agent):
		browserVersion = FindSubMatch(`(?i)FireFox\/([^\s]+)`, agent)[1]
		browser = "FireFox"
	case IsMatchPattern(`(?i)Lynx\/([^\s]+)`, agent):
		browserVersion = FindSubMatch(`(?i)Lynx\/([^\s]+)`, agent)[1]
		browser = "Lynx"
	case IsMatchPattern(`(?i)Chrome\/([^\s]+)`, agent):
		browserVersion = FindSubMatch(`(?i)Chrome\/([^\s]+)`, agent)[1]
		browser = "Chrome"
	}
	if browser != "" {
		return map[string]string{"browser": browser, "version": browserVersion}
	}
	return map[string]string{"browser": "unknown browser", "version": "unknown browser version"}
}

func PidsStrToPidsInt64(pids []string) []int64 {
	converted := []int64{}
	for _, one := range pids {
		converted = append(converted, StringToInt64(one))
	}
	return converted
}

func PidsStrToPidsInt(pids []string) []int {
	converted := []int{}
	for _, one := range pids {
		converted = append(converted, StringToInt(one))
	}
	return converted
}

func PidsIntToPidsStr(pids []int64) []string {
	converted := []string{}
	for _, one := range pids {
		converted = append(converted, ToString(one))
	}
	return converted
}

func RemoveStrSpace(s []string) []string {
	temp := []string{}
	for _, one := range s {
		if one != "" {
			temp = append(temp, one)
		}
	}
	return temp
}
